# add module path to PYTHONPATH ta make it working

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support.expected_conditions import *

addIcon      = "Add movie"
updateIcon   = "Update all"
exportIcon   = "Export"
saveIcon     = "Save"
ownIcon      = "Own"
seenIcon     = "Seen"
editIcon     = "Edit"
removeIcon   = "Remove"
visitIcon    = "Visit IMDb"
trailerIcon  = "View trailer"
coverIcon    = "Download cover"

def setUpTest(TestCase):
    """perform test case Set Up"""
    TestCase.driver = webdriver.Firefox()
    TestCase.driver.implicitly_wait(10)
    TestCase.base_url = "http://localhost/php4dvd/"
    TestCase.verificationErrors = []

def tearDownTest(TestCase):
    """perform test case Tear Down"""
    TestCase.driver.quit()
    TestCase.assertEqual([], TestCase.verificationErrors)

def accept_alert_and_get_its_text(TestCase):
    alert = TestCase.driver.switch_to_alert()
    text = alert.text
    alert.accept()
    return text

def cancel_alert_and_get_its_text(TestCase):
    alert = TestCase.driver.switch_to_alert()
    text = alert.text
    alert.dismiss()
    return text

def is_element_present(where, how, what):
    try: where.find_element(by=how, value=what)
    except NoSuchElementException, e: return False
    return True

def logIn(TestCase, username, password):
    """perform Log In steps"""
    TestCase.driver.get(TestCase.base_url)
    TestCase.driver.find_element_by_id("username").clear()
    TestCase.driver.find_element_by_id("username").send_keys(username)
    TestCase.driver.find_element_by_name("password").clear()
    TestCase.driver.find_element_by_name("password").send_keys(password)
    TestCase.driver.find_element_by_name("submit").click()
    # return list of movies in catalogue
    return verifyCatalogue(TestCase)

def clickAddMovie(TestCase):
    """perform Add movie icon click"""
    TestCase.driver.find_element_by_css_selector("img[alt=\"Add movie\"]").click()
    # assert naigation panel presence with 'Save' icon only
    TestCase.assertTrue(checkNavigationPanel(TestCase, [saveIcon]))
    # assert 'Movie information' page opens
    TestCase.assertTrue(is_element_present(TestCase.driver, By.ID, "updateform"))

def clickRemoveMovie(TestCase):
    """perform Remove movie icon click"""
    # click Remove icon
    TestCase.driver.find_element_by_css_selector("img[alt=\"Remove\"]").click()
    # close alert message and check its text
    TestCase.assertRegexpMatches(accept_alert_and_get_its_text(TestCase),
                                 r"^Are you sure you want to remove this[\s\S]$")
    return verifyCatalogue(TestCase)

def checkNavigationPanel(TestCase, presentIconList):
    """perform navigation panel verifcation
       presentIconList - list of icons to be present"""
    # locate navigation panel
    nav = TestCase.driver.find_element_by_css_selector("section > nav")
    # get list of icons
    displayed_icons = nav.find_elements_by_xpath("//div/a/img")
    # get list of icon titles
    displayed_icon_titles = [icon.get_attribute("title") for icon in displayed_icons]
    # compare expected list with actual list
    return displayed_icon_titles == presentIconList

def verifyCatalogue(TestCase):
    """verify correct icons are displayed in navigation panel, search box is present, catalogue is displayed"""
    # assert navigation panel displays corect icons
    TestCase.assertTrue(checkNavigationPanel(TestCase, [addIcon, updateIcon, exportIcon]))
    # assert Search box is present
    TestCase.assertTrue(is_element_present(TestCase.driver, By.ID, "q"))
    # create list of movies
    movieElementList = TestCase.driver.find_elements_by_xpath("//section/div[3]/a/div/div[2]")
    # return list of movie titles
    return [elem.text for elem in movieElementList]

def moviePopulateValues(TestCase):
    """perform entering values to 'Add movie' or 'Edit moie' form
       if any attribute is None, it won't be changed"""
    # populate corresponding values to the form
    for name, value in TestCase.movieDataDict.items():
        # skip if value is None 
        if value is not None:
            # set radio controls
            if name in ["own", "seen", "loaned"]:
                if value:
                    TestCase.driver.find_element_by_id(name+"_yes").click()
                else:
                    TestCase.find_element_by_id(name+"_no").click()
            # set value by element id
            elif name not in ["loanname", "loandate"]:
                TestCase.driver.find_element_by_name(name).clear
                TestCase.driver.find_element_by_name(name).send_keys(value)
    # set values of hidden text boxes if they become visible
    if TestCase.movieDataDict["loaned"]:
        if TestCase.movieDataDict["loanname"] is not None:
            TestCase.driver.find_element_by_name("loanname").clear()
            TestCase.driver.find_element_by_name("loanname").send_keys(TestCase.movieDataDict["loanname"])
        if TestCase.movieDataDict["loandate"] is not None:
            TestCase.driver.find_element_by_name("loandate").clear()
            TestCase.driver.find_element_by_name("loandate").send_keys(TestCase.movieDataDict["loandate"])

def movieSave(TestCase, bySaveIcon):
    """perform save for 'Add movie' or 'Edit movie' form
       if bySaveIcon is True then form is saves by Save icon click, esle by Submit button click"""
    if bySaveIcon:
        TestCase.driver.find_element_by_css_selector("img[alt=\"Save\"]").click()
    else:
        TestCase.driver.find_element_by_id("submit").click()
    # here goes verification of entered information
    # currently only some parameters are verified
    nav = TestCase.driver.find_element_by_css_selector("section > nav")
    # create list of icons to check against navigation panel
    iconList = []
    # check IMDb number if it was provided 
    if TestCase.movieDataDict["imdbid"]:
        # check Visit IMDb icon's href
        link = nav.find_element_by_xpath("//li/div/div/a").get_attribute("href")
        TestCase.assertTrue(link == "http://www.imdb.com/title/tt"+TestCase.movieDataDict["imdbid"]+"/")
        # add icon to the list
        iconList.append(visitIcon)
    # check Trailer URL if it was provided
    if TestCase.movieDataDict["trailer"]:
        # check View trailer icon's href 
        xpath = "//li[2]/div/div/a" if iconList else "//li/div/div/a"
        link = nav.find_element_by_xpath(xpath).get_attribute("href")
        TestCase.assertTrue(link == TestCase.movieDataDict["trailer"]+"/?iframe=true&width=100%&height=100%")
        # add icon to the list
        iconList.append(trailerIcon)
    # check Cover if it was provided
    if TestCase.movieDataDict["cover"]:
        # check coer image tag is present
        TestCase.assertTrue(is_element_present(TestCase.driver, By.XPATH,
                                               "/html/body/div/div/div/section/div/div/div/img"))
        # add icon to the list
        iconList.append(coverIcon)
    # check movie name and year
    h2 = TestCase.driver.find_element_by_xpath("/html/body/div/div/div/section/div/div/div[2]/h2")
    TestCase.assertTrue(h2.text == TestCase.movieDataDict["name"]+" ("+TestCase.movieDataDict["year"]+")")
    # check navigation menu
    iconList += [ownIcon, seenIcon, editIcon, removeIcon]
    TestCase.assertTrue(checkNavigationPanel(TestCase, iconList))
    
def movieSaveInvalid(TestCase, bySaveIcon):
    """perform save for 'Add movie' or 'Edit movie' form with empty required field
       if bySaveIcon is True then form is saves by Save icon click, esle by Submit button click"""
    if bySaveIcon:
        TestCase.driver.find_element_by_css_selector("img[alt=\"Save\"]").click()
    else:
        TestCase.driver.find_element_by_id("submit").click()
    # check required field labels are displayed
    if not TestCase.movieDataDict["name"]:
        label = TestCase.driver.find_element_by_xpath("//table/tbody/tr[2]/td[2]/label")
        TestCase.assertTrue(label.text == "This field is required")
    if not TestCase.movieDataDict["year"]:
        label = TestCase.driver.find_element_by_xpath("//table/tbody/tr[4]/td[2]/label")
        TestCase.assertTrue(label.text == "This field is required")

def locateMovieByName(TestCase):
    """find and return first occurance of movie element with given name"""
    elementList = TestCase.driver.find_elements_by_xpath("//section/div[3]/a/div/div[2]")
    for element in elementList:
        if element.text == TestCase.movieToRemove:
            break
    return element

def goHomeMenu(TestCase):
    """navigate to catalogue by clicking Home menu item"""
    TestCase.driver.find_element_by_link_text("Home").click()
    return verifyCatalogue(TestCase)

def addMovieToCatalogue(TestCase):
    """utility function to add movie with minimum verifications"""
    goHomeMenu(TestCase)
    clickAddMovie(TestCase)
    moviePopulateValues(TestCase)
    movieSave(TestCase, bySaveIcon = False)
    return goHomeMenu(TestCase)

def searchForMovie(TestCase):
    """perform movie searching by entering text to search box"""
    TestCase.driver.find_element_by_id("q").clear()
    if TestCase.movieToSearch:
        TestCase.driver.find_element_by_id("q").send_keys(TestCase.movieToSearch)
    TestCase.driver.find_element_by_id("q").send_keys(Keys.RETURN)
    wait = WebDriverWait(TestCase.driver, 10)
    # check 'loading' progress bar is displayed while searching
    TestCase.assertTrue(wait.until(visibility_of_element_located((By.ID, "loading"))))
    # check catalogue is displayed after searching done
    TestCase.assertTrue(wait.until(visibility_of_element_located((By.ID, "results"))))
    return verifyCatalogue(TestCase)
